package com.baidu.sggc.core;

import com.baidu.sggc.core.annotation.AuditLog;
import com.baidu.sggc.core.common.utils.AuditLogUtil;
import com.baidu.sggc.entity.UserContext;
import com.baidu.sggc.audit.extend.AuditExtendContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 审计日志AOP切面
 */
@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class AuditLogAspect {

    private final AuditLogUtil auditLogUtil;
    private final ObjectMapper objectMapper; // 单例注入，避免重复创建

    @Around("@annotation(auditLog)")
    public Object around(ProceedingJoinPoint joinPoint, AuditLog auditLog) throws Throwable {
        long startTime = System.currentTimeMillis();
        String operateState = "success";
        String errorMessage = "";

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes != null ? attributes.getRequest() : null;

        Object result = null;
        try {
            // 执行目标方法
            result = joinPoint.proceed();
        } catch (Exception e) {
            operateState = "failed";
            errorMessage = ": " + e.getMessage();
            throw e;
        } finally {
            // 无论是否异常，都尝试记录审计日志
            try {
                String userId = UserContext.getUserId();
                String userName = UserContext.getUserName();

                // 验证必填字段
                if (userId == null || userName == null) {
                    log.warn("用户信息为空，跳过审计日志记录");
                } else if (request == null) {
                    log.warn("无法获取当前请求上下文，跳过审计日志记录");
                } else {
                    // 判断是否为查询类操作
                    String operationType = auditLog.operation();
                    boolean isQueryOperation = "listQuery".equalsIgnoreCase(operationType)
                            || "detailQuery".equalsIgnoreCase(operationType);

                    // 修复：将return逻辑提取到条件判断中，避免在finally块中return
                    boolean shouldSkipAudit = false;
                    if (isQueryOperation) {
                        String needAudit = request.getHeader("X-Bce-Audit-Need-Audit");
                        if (!"true".equalsIgnoreCase(needAudit)) {
                            log.info("查询类操作且未标记需要审计，跳过记录");
                            shouldSkipAudit = true;
                        }
                    }

                    if (!shouldSkipAudit) {
                        // 获取并解码菜单路径
                        String menuPath = request.getHeader("X-Bce-Audit-Menu-Path");
                        if (menuPath == null || menuPath.trim().isEmpty()) {
                            menuPath = "未知菜单";
                        } else {
                            try {
                                menuPath = URLDecoder.decode(menuPath, StandardCharsets.UTF_8.name());
                            } catch (Exception e) {
                                log.warn("菜单路径URL解码失败: {}", menuPath, e);
                            }
                        }

                        String message = auditLog.message() + errorMessage;

                        // 构建审计日志对象
                        com.baidu.sggc.entity.AuditLog logEntity = auditLogUtil.buildAuditLog(
                                userId, userName,
                                auditLog.module(), auditLog.auditObject(),
                                operationType, message,
                                request, menuPath, operateState
                        );
                        logEntity.setEventType(auditLog.eventType());

                        // 设置扩展字段
                        Map<String, Object> extendMap = AuditExtendContext.getExtendData();
                        if (extendMap != null && !extendMap.isEmpty()) {
                            String extendJson = objectMapper.writeValueAsString(extendMap);
                            logEntity.setExtendData(extendJson);
                        }

                        // 异步保存日志
                        auditLogUtil.saveAuditLogAsync(logEntity);

                        long endTime = System.currentTimeMillis();
                        log.info("审计日志记录完成，耗时: {}ms", endTime - startTime);
                    }
                }
            } catch (Exception e) {
                log.error("AOP记录审计日志失败", e);
            } finally {
                AuditExtendContext.clear(); // 避免内存泄漏
            }
        }

        return result;
    }

}